/**
 * @file    porttimer.c
 * @brief   FreeModbus定时器移植层实现
 * @details 本文件实现了FreeModbus协议栈在STM32平台上的定时器功能，主要用于RTU模式下的
 *          字符间超时检测和帧间隔检测。使用TIM7定时器提供50μs精度的定时功能。
 */

#include "mb.h"             /* FreeModbus核心头文件 */
#include "mbport.h"         /* FreeModbus移植层接口头文件 */
#include "port_internal.h"  /* 内部移植层定义头文件 */
#include "main.h"           /* 主程序头文件，包含GPIO定义 */

static TIM_HandleTypeDef h_tim7;    /* TIM7定时器句柄，配置为50μs周期 */
static USHORT timeout = 0;          /* 定时器超时值，单位为50μs */
static USHORT downcounter = 0;      /* 定时器递减计数器，每50μs递减1 */

/**
 * @brief 初始化FreeModbus定时器
 * @details 配置TIM7为50μs基础定时器，用于RTU模式字符间超时检测
 * @param usTim1Timerout50us 超时时间，单位为50μs
 * @return BOOL 初始化结果
 */
BOOL xMBPortTimersInit( USHORT usTim1Timerout50us )
{
    /* 使能TIM7定时器时钟 */
    __HAL_RCC_TIM7_CLK_ENABLE();

    TIM_MasterConfigTypeDef sMasterConfig;
    
    /* 配置TIM7基本参数 */
    h_tim7.Instance = TIM7;                                         /* 使用TIM7定时器 */
    h_tim7.Init.Prescaler = (HAL_RCC_GetPCLK1Freq() / 1000000) - 1; /* 预分频到1MHz（1μs分辨率） */
    h_tim7.Init.CounterMode = TIM_COUNTERMODE_UP;                   /* 向上计数模式 */
    h_tim7.Init.Period = 50 - 1;                                    /* 周期50μs */

    /* 保存超时参数，用于后续的定时器启用 */
    timeout = usTim1Timerout50us;

    /* 初始化定时器基础配置 */
    if (HAL_TIM_Base_Init(&h_tim7) != HAL_OK)
    {
        return FALSE;  /* 定时器初始化失败 */
    }

    /* 配置定时器主模式（通常用于触发其他外设，这里设为标准配置） */
    sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;             /* 更新事件作为触发输出 */
    sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;     /* 禁用主从模式 */
    if (HAL_TIMEx_MasterConfigSynchronization(&h_tim7, &sMasterConfig) != HAL_OK)
    {
        return FALSE;  /* 主模式配置失败 */
    }

    /* 配置NVIC中断控制器，设置TIM7中断优先级 */
    HAL_NVIC_SetPriority(TIM7_IRQn, MB_TIM7_IRQ_priority, MB_TIM7_IRQ_subpriority);
    
    /* 配置调试输出引脚（条件编译） */
    #if MB_TIMER_DEBUG == 1
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    
    /* 配置调试GPIO引脚参数 */
    GPIO_InitStruct.Pin = MB_TIMER_DEBUG_PIN;           /* 调试引脚编号 */
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;         /* 推挽输出模式 */
    GPIO_InitStruct.Pull = GPIO_NOPULL;                 /* 无上下拉 */
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;        /* 低速输出（调试用途） */
    HAL_GPIO_Init(MB_TIMER_DEBUG_PORT, &GPIO_InitStruct);
    
    /* 初始状态设为低电平 */
    vMBTimerDebugSetLow();
    #endif

    return TRUE;  /* 初始化成功 */
}

/**
 * @brief 启用FreeModbus定时器
 * @details 启动TIM7定时器并开始倒计时，用于检测RTU模式下的字符间超时
 */
void vMBPortTimersEnable( void )
{
    /* 使用初始化时传入的超时值重新加载倒计时计数器 */
    downcounter = timeout;
    
    /* 设置调试引脚为高电平，指示定时器处于活动状态 */
    vMBTimerDebugSetHigh();
    
    /* 启动TIM7基础定时器并使能中断 */
    HAL_TIM_Base_Start_IT(&h_tim7);
    
    /* 在NVIC中启用TIM7中断 */
    HAL_NVIC_EnableIRQ(TIM7_IRQn);
}

/**
 * @brief 禁用FreeModbus定时器
 * @details 停止TIM7定时器并禁用相关中断，停止RTU模式下的超时检测
 */
void vMBPortTimersDisable( void )
{
    /* 停止TIM7基础定时器并禁用中断 */
    HAL_TIM_Base_Stop_IT(&h_tim7);
    
    /* 在NVIC中禁用TIM7中断 */
    HAL_NVIC_DisableIRQ(TIM7_IRQn);
    
    /* 设置调试引脚为低电平，指示定时器已禁用 */
    vMBTimerDebugSetLow();
}

/**
 * @brief FreeModbus TIM7定时器中断服务程序
 * @details 处理TIM7更新中断，每50μs递减downcounter，为0时触发超时回调
 */
void TIM7_IRQHandler( void )
{
    /* 检查TIM7更新中断标志和中断使能状态 */
    if(__HAL_TIM_GET_FLAG(&h_tim7, TIM_FLAG_UPDATE) != RESET && 
       __HAL_TIM_GET_IT_SOURCE(&h_tim7, TIM_IT_UPDATE) != RESET) 
    {
        /* 清除更新中断标志，防止重复触发 */
        __HAL_TIM_CLEAR_IT(&h_tim7, TIM_IT_UPDATE);

        /* 递减downcounter并检查是否达到0（超时） */
        if (--downcounter == 0) 
        {
            /* 定时器超时，设置调试引脚为低电平指示超时事件 */
            vMBTimerDebugSetLow();
            
            /* 调用FreeModbus协议栈的超时回调函数 */
            pxMBPortCBTimerExpired();
        }
    }

    /* 调用HAL库的通用定时器中断处理函数，处理其他可能的中断源 */
    HAL_TIM_IRQHandler(&h_tim7);
}
